﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace GroupsExample
{
    public class UserContext:DbContext
    {
        public DbSet<User> Users { get; set; }

        public DbSet<Connection> Connections { get; set; }

        public DbSet<ConversationRoom> Rooms { get; set; }
    }

    public class ConversationRoom
    {
        [Key]
        public string RoomName { get; set; }

        public virtual ICollection<User> Users { get; set; }
    }

    public class Connection
    {
        public string ConnectionId { get; set; }
        public string UserAgent { get; set; }
        public bool Connected { get; set; }
    }

    public class User
    {
        [Key]
        public string UserName { get; set; }

        public ICollection<Connection> Connections { get; set; }
        public virtual ICollection<ConversationRoom> Rooms { get; set; }
    }

    [Authorize]
    public class ChatHub : Hub
    {
        public override Task OnConnected()
        {
            using (var db=new UserContext())
            {
                var user = db.Users
                    .Include(u => u.Rooms)
                    .SingleOrDefault(u => u.UserName == Context.User.Identity.Name);

                if (user == null)
                {
                    user=new User()
                    {
                        UserName = Context.User.Identity.Name
                    };
                    db.Users.Add(user);
                    db.SaveChanges();
                }
                else
                {
                    foreach (var item in user.Rooms)
                    {
                        Groups.Add(Context.ConnectionId, item.RoomName);
                    }
                }

                return base.OnConnected();
            }
        }

        public void AddToRoom(string roomName)
        {
            using (var db=new UserContext())
            {
                var room = db.Rooms.Find(roomName);

                if (room!=null)
                {
                    var user=new User()
                    {
                        UserName = Context.User.Identity.Name
                    };
                    db.Users.Attach(user);
                    room.Users.Add(user);
                    db.SaveChanges();
                    Groups.Add(Context.ConnectionId, roomName);
                }
            }
        }

        public void RemoveFromRoom(string roomName)
        {
            using (var db=new UserContext())
            {
                var room = db.Rooms.Find(roomName);
                if (room!=null)
                {
                    var user=new User(){UserName = Context.User.Identity.Name};
                    db.Users.Attach(user);

                    room.Users.Remove(user);
                    db.SaveChanges();

                    Groups.Remove(Context.ConnectionId, roomName);
                }
            }
        }

        public class RejoingGroupPipelineModule :HubPipelineModule
        {
            public override Func<HubDescriptor, IRequest, IList<string>, IList<string>> BuildRejoiningGroups(
                Func<HubDescriptor, IRequest, IList<string>, IList<string>> rejoiningGroups)
            {
                rejoiningGroups = (hb, r, l) =>
                {
                    List<string> assignedRoom = new List<string>();
                    using (var db = new UserContext())
                    {
                        var user = db.Users
                            .Include(u => u.Rooms)
                            .Single(u => u.UserName == r.User.Identity.Name);
                        foreach (var item in user.Rooms)
                        {
                            assignedRoom.Add(item.RoomName);
                        }
                    }

                    return assignedRoom;
                };

                return rejoiningGroups;
            }
        }
    }
}